using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using DataService.Helper;
using Newtonsoft.Json;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Client.Controls;
using Opc.Ua.Sample.Service;
using OpcuaClient.Model;
using Org.BouncyCastle.Utilities;

namespace OpcuaClient.Service
{
    public class CollectWriteService
    {
        LogHelper LogHelper = new LogHelper("OpcuaClient");
        public OpcConnectService OpcConnectService { get; set; }
        public Collection Collection { get; set; }
        public CollectReadService CollectionReadService { get; set; }
        private bool IsRead { get; set; }

        private event EventHandler m_ValueChange;
        private event EventHandler m_ReadError;
        /// <summary>
        /// Raised after a node is selected in the control.
        /// </summary>
        public event EventHandler AfterValueChanged { add { m_ValueChange += value; } remove { m_ValueChange -= value; } }
        /// <summary>
        /// Raised after a node is deleted in the control.
        /// </summary>
        public event EventHandler ReadError { add { m_ReadError += value; } remove { m_ReadError -= value; } }
        public CollectWriteService() { }

        public CollectWriteService(OpcConnectService connectService, Collection collection)
        {
            OpcConnectService = connectService;
            Collection = collection;
            LogHelper = new LogHelper(OpcConnectService.Server.Code);
        }
        /// <summary>
        /// 初始化写逻辑
        /// </summary>
        public void StartWrite()
        {
            CollectionReadService = OpcConnectService.CollectionServiceList.FirstOrDefault(m => m.Collection.Key == Collection.Precondition);
            if (CollectionReadService == null)
            {
                LogHelper.Error($"Write:{OpcConnectService.Server.Code}-{Collection.Name} 写入前置条件不能为空！");
                return;
            }
            CollectionReadService.AfterValueChanged += new EventHandler(WriteHandler);
        }

        #region 写入
        /// <summary>
        /// Reads the values displayed in the control and moves to the display results state.
        /// </summary>
        public void WriteHandler(object obj, EventArgs e)
        {
            // build list of values to write.
            WriteValueCollection writeValues = null;
            switch (Collection.WriteType)
            {
                case "WaferId": writeValues = CreateWaferId(); break;
                case "Value": writeValues = CreateValue(); break;
            }
            if (writeValues == null) return;
            WriteValue(writeValues);
        }

        /// <summary>
        /// 写入值
        /// </summary>
        /// <exception cref="ServiceResultException"></exception>
        private void WriteValue(WriteValueCollection writeCollection)
        {
            try
            {
                if (writeCollection == null) return;
                Session m_session = OpcConnectService.Session;
                if (m_session == null)
                {
                    throw new ServiceResultException(StatusCodes.BadNotConnected);
                }

                // read the values.
                StatusCodeCollection results = null;
                DiagnosticInfoCollection diagnosticInfos = null;

                var header = m_session.Write(
                    null,
                    writeCollection,
                    out results,
                    out diagnosticInfos);

                ClientBase.ValidateResponse(results, writeCollection);
                ClientBase.ValidateDiagnosticInfos(diagnosticInfos, writeCollection);
                LogHelper.Info($"{OpcConnectService.Server.Name}-{Collection.Name}:{JsonConvert.SerializeObject(writeCollection)}");
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex.Message + "\r\n" + ex.StackTrace);
            }
        }
        #region Value
        private WriteValueCollection CreateValue()
        {
            WriteValueCollection nodesToWrite = new WriteValueCollection();
            WriteValue writeValue = CreateWriteValue(Collection.Prefix);
            switch (Collection.DataType)
            {
                case "String":
                    writeValue = CreateWriteValue(Collection.Prefix);
                    break;
                case "Int":
                    int value = int.Parse(Collection.Prefix);
                    writeValue = CreateWriteValue(value);
                    break;
                case "Float":
                    float floatValue = float.Parse(Collection.Prefix);
                    writeValue = CreateWriteValue(floatValue);
                    break;
                case "Double":
                    double doubleValue = int.Parse(Collection.Prefix);
                    writeValue = CreateWriteValue(doubleValue);
                    break;
                case "Bool":
                    bool boolValue = bool.Parse(Collection.Prefix);
                    writeValue = CreateWriteValue(boolValue);
                    break;
            }
            nodesToWrite.Add(writeValue);
            return nodesToWrite;
        }
        #endregion

        /// <summary>
        /// 生产WaferID
        /// </summary>
        /// <param name="count"></param>
        /// <returns></returns>
        private WriteValueCollection CreateWaferId(int count = 120)
        {
            WriteValueCollection nodesToWrite = new WriteValueCollection();
            int idx = 0;
            List<string> wafers = new List<string>();
            while (idx < count)
            {
                wafers.Add($"{Collection.Prefix}{DateTimeOffset.Now.ToUnixTimeSeconds() + idx}");
                idx++;
            }
            WriteValue writeValue = CreateWriteValue(wafers.ToArray());
            nodesToWrite.Add(writeValue);
            return nodesToWrite;
        }

        /// <summary>
        /// 创建一个定稿值
        /// </summary>
        /// <param name="value"></param>
        /// <param name="indx"></param>
        /// <returns></returns>
        private WriteValue CreateWriteValue(object value)
        {
            DataValue dataValue = CreateDataValue(value);

            WriteValue writeValue = new WriteValue();
            writeValue.NodeId = Collection.Node;
            writeValue.AttributeId = Attributes.Value;
            writeValue.Value = dataValue;
            writeValue.Value.WrappedValue = new Variant(value);

            return writeValue;
        }

        /// <summary>
        /// 创建一个值
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private DataValue CreateDataValue(object value)
        {
            Variant variant = new Variant(value);
            DataValue dataValue = new DataValue(variant);
            return dataValue;
        }
        #endregion
    }
}
